home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / WORDPAD.PAK / WORDPAD.CPP < prev    next >
C/C++ Source or Header  |  1997-05-06  |  27KB  |  904 lines

  1. // wordpad.cpp : Defines the class behaviors for the application.
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1995 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14.  
  15. #include "wordpad.h"
  16. #include "mainfrm.h"
  17. #include "ipframe.h"
  18. #include "wordpdoc.h"
  19. #include "wordpvw.h"
  20. #include "strings.h"
  21. #include "key.h"
  22. #include "filenewd.h"
  23. #include <locale.h>
  24. #include <winnls.h>
  25. #include <winreg.h>
  26.  
  27. extern BOOL AFXAPI AfxFullPath(LPTSTR lpszPathOut, LPCTSTR lpszFileIn);
  28. static BOOL RegisterHelper(LPCTSTR* rglpszRegister, LPCTSTR* rglpszSymbols, 
  29.     BOOL bReplace);
  30.  
  31. #ifdef _DEBUG
  32. #undef THIS_FILE
  33. static char BASED_CODE THIS_FILE[] = __FILE__;
  34. #endif
  35.  
  36. CLIPFORMAT cfEmbeddedObject;
  37. CLIPFORMAT cfRTF;
  38. CLIPFORMAT cfRTO;
  39.  
  40. int CWordPadApp::m_nOpenMsg = RegisterWindowMessage(_T("WordPadOpenMessage"));
  41. int CWordPadApp::m_nPrinterChangedMsg = RegisterWindowMessage(_T("WordPadPrinterChanged"));
  42.  
  43. const int CWordPadApp::m_nPrimaryNumUnits = 4;
  44. const int CWordPadApp::m_nNumUnits = 7;
  45.  
  46. CUnit CWordPadApp::m_units[7] = 
  47. {
  48. //    TPU,     SmallDiv,    MedDiv,    LargeDiv,    MinMove,    szAbbrev,            bSpace
  49. CUnit(1440,    180,        720,    1440,        90,            IDS_INCH1_ABBREV,    FALSE),//inches
  50. CUnit(568,    142,        284,    568,        142,        IDS_CM_ABBREV,        TRUE),//centimeters
  51. CUnit(20,    120,        720,    720,        100,        IDS_POINT_ABBREV,    TRUE),//points
  52. CUnit(240,    240,        1440,    1440,        120,        IDS_PICA_ABBREV,    TRUE),//picas
  53. CUnit(1440,    180,        720,    1440,        90,            IDS_INCH2_ABBREV,    FALSE),//in
  54. CUnit(1440,    180,        720,    1440,        90,            IDS_INCH3_ABBREV,    FALSE),//inch
  55. CUnit(1440,    180,        720,    1440,        90,            IDS_INCH4_ABBREV,    FALSE)//inches
  56. };
  57.  
  58. static UINT DoRegistry(LPVOID lpv)
  59. {
  60.     ASSERT(lpv != NULL);
  61.     ((CWordPadApp*)lpv)->UpdateRegistry();
  62.     return 0;
  63. }
  64.  
  65. /////////////////////////////////////////////////////////////////////////////
  66. // CWordPadApp
  67.  
  68. BEGIN_MESSAGE_MAP(CWordPadApp, CWinApp)
  69.     //{{AFX_MSG_MAP(CWordPadApp)
  70.     ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
  71.     ON_COMMAND(ID_FILE_NEW, OnFileNew)
  72.     ON_COMMAND(ID_FILE_OPEN, OnFileOpen)
  73.     //}}AFX_MSG_MAP
  74. END_MESSAGE_MAP()
  75.  
  76. void CWordPadCommandLineInfo::ParseParam(const char* pszParam,BOOL bFlag,BOOL bLast)
  77. {
  78.     if (bFlag)
  79.     {
  80.         if (lstrcmpA(pszParam, "t") == 0)
  81.         {
  82.             m_bForceTextMode = TRUE;
  83.             return;
  84.         }
  85.     }
  86.     CCommandLineInfo::ParseParam(pszParam, bFlag, bLast);
  87. }
  88.  
  89. /////////////////////////////////////////////////////////////////////////////
  90. // CWordPadApp construction
  91.  
  92. CWordPadApp::CWordPadApp() : m_optionsText(0), m_optionsRTF(1), 
  93.     m_optionsWord(2), m_optionsWrite(2), m_optionsIP(2), m_optionsNull(0)  // 
  94. {
  95.     _tsetlocale(LC_ALL, _T(""));
  96.  
  97.     m_nFilterIndex = 1;
  98.     DWORD dwVersion = ::GetVersion();
  99.     m_bWin4 = (BYTE)dwVersion >= 4;
  100. #ifndef _UNICODE
  101.     m_bWin31 = (dwVersion > 0x80000000 && !m_bWin4);
  102. #endif
  103.     m_nDefFont = (m_bWin4) ? DEFAULT_GUI_FONT : ANSI_VAR_FONT;
  104.     m_dcScreen.Attach(::GetDC(NULL));
  105.     m_bLargeIcons = m_dcScreen.GetDeviceCaps(LOGPIXELSX) >= 120;
  106.     m_bForceOEM = FALSE;
  107. }
  108.  
  109. CWordPadApp::~CWordPadApp()
  110. {
  111.     if (m_dcScreen.m_hDC != NULL)
  112.         ::ReleaseDC(NULL, m_dcScreen.Detach());
  113. }
  114.  
  115. /////////////////////////////////////////////////////////////////////////////
  116. // The one and only CWordPadApp object
  117.  
  118. CWordPadApp theApp;
  119.  
  120. // Register the application's document templates.  Document templates
  121. //  serve as the connection between documents, frame windows and views.
  122. static CSingleDocTemplate DocTemplate(
  123.         IDR_MAINFRAME,
  124.         RUNTIME_CLASS(CWordPadDoc),
  125.         RUNTIME_CLASS(CMainFrame),       // main SDI frame window
  126.         RUNTIME_CLASS(CWordPadView));
  127.  
  128. // This identifier was generated to be statistically unique for your app.
  129. // You may change it if you prefer to choose a specific identifier.
  130. static const CLSID BASED_CODE clsid =
  131. { 0x73FDDC80L, 0xAEA9, 0x101A, { 0x98, 0xA7, 0x00, 0xAA, 0x00, 0x37, 0x49, 0x59} };
  132.  
  133. /////////////////////////////////////////////////////////////////////////////
  134. // CWordPadApp initialization
  135.  
  136. BOOL CWordPadApp::InitInstance()
  137. {
  138.     ParseCommandLine(cmdInfo);
  139.  
  140.     if (::FindWindow(szWordPadClass, NULL) && IsDocOpen(cmdInfo.m_strFileName))
  141.         return FALSE;
  142.  
  143.     SetRegistryKey(szRegKey);
  144.     LoadOptions();
  145.  
  146.     Enable3dControls();
  147.     CSplashWnd splash;
  148.     BOOL bSplash = cmdInfo.m_bShowSplash;
  149.     if (!cmdInfo.m_bRunEmbedded)
  150.     {
  151.         switch (m_nCmdShow)
  152.         {
  153.             case SW_HIDE:
  154.             case SW_SHOWMINIMIZED:
  155.             case SW_MINIMIZE:
  156.             case SW_SHOWMINNOACTIVE:
  157.                 bSplash = FALSE;
  158.                 break;
  159.             case SW_RESTORE:
  160.             case SW_SHOW:
  161.             case SW_SHOWDEFAULT:
  162.             case SW_SHOWNA:
  163.             case SW_SHOWNOACTIVATE:
  164.             case SW_SHOWNORMAL:
  165.             case SW_SHOWMAXIMIZED:
  166.                 if (m_bMaximized)
  167.                     m_nCmdShow = SW_SHOWMAXIMIZED;
  168.                 break;
  169.         }
  170.     }
  171.     else
  172.     {
  173.          //Excel 4 will start OLE servers minimized
  174.          m_nCmdShow = SW_SHOWNORMAL;
  175.     }
  176.     int nCmdShow = m_nCmdShow;
  177.  
  178.     if (bSplash)
  179.     {
  180.         // only show splash if not embedded
  181.         splash.Create(NULL);
  182.         splash.ShowWindow(SW_SHOW);
  183.         splash.UpdateWindow();
  184.     }
  185.  
  186.     LoadAbbrevStrings();
  187.  
  188.     m_hDevNames = CreateDevNames();
  189.     NotifyPrinterChanged((m_hDevNames == NULL));
  190.  
  191.     m_pszHelpFilePath = _T("WORDPAD.HLP");
  192.  
  193.     // Initialize OLE libraries
  194.     if (!AfxOleInit())
  195.     {
  196.         AfxMessageBox(IDP_OLE_INIT_FAILED);
  197.         return FALSE;
  198.     }
  199.     RegisterFormats();
  200.  
  201.     // Initialize RichEdit control
  202.     if (LoadLibrary(_T("RICHED32.DLL")) == NULL)
  203.     {
  204.         AfxMessageBox(IDS_RICHED_LOAD_FAIL, MB_OK|MB_ICONEXCLAMATION);
  205.         return FALSE;
  206.     }
  207.  
  208.     // Standard initialization
  209.     // If you are not using these features and wish to reduce the size
  210.     //  of your final executable, you should remove from the following
  211.     //  the specific initialization routines you do not need.
  212.  
  213.     LoadStdProfileSettings();  // Load standard INI file options (including MRU)
  214.  
  215.     // Register the application's document templates.  Document templates
  216.     //  serve as the connection between documents, frame windows and views.
  217.  
  218.     DocTemplate.SetContainerInfo(IDR_CNTR_INPLACE);
  219.     DocTemplate.SetServerInfo(
  220.         IDR_SRVR_EMBEDDED, IDR_SRVR_INPLACE,
  221.         RUNTIME_CLASS(CInPlaceFrame));
  222.  
  223.     // Connect the COleTemplateServer to the document template.
  224.     //  The COleTemplateServer creates new documents on behalf
  225.     //  of requesting OLE containers by using information
  226.     //  specified in the document template.
  227.     m_server.ConnectTemplate(clsid, &DocTemplate, TRUE);
  228.         // Note: SDI applications register server objects only if /Embedding
  229.         //   or /Automation is present on the command line.
  230.  
  231.     // Check to see if launched as OLE server
  232.     if (cmdInfo.m_bRunEmbedded || cmdInfo.m_bRunAutomated)
  233.     {
  234.         // Register all OLE server (factories) as running.  This enables the
  235.         //  OLE libraries to create objects from other applications.
  236.         COleTemplateServer::RegisterAll();
  237.         AfxOleSetUserCtrl(FALSE);
  238.  
  239.         // Application was run with /Embedding or /Automation.  Don't show the
  240.         //  main window in this case.
  241.         return TRUE;
  242.     }
  243.  
  244.     // make sure the main window is showing 
  245.     m_bPromptForType = FALSE;
  246.     OnFileNew();
  247.     m_bPromptForType = TRUE;
  248.     // destroy splash window
  249.     if (cmdInfo.m_bShowSplash)
  250.         splash.DestroyWindow();
  251.     m_nCmdShow = -1;
  252.     if (m_pMainWnd == NULL) // i.e. OnFileNew failed
  253.         return FALSE;
  254.  
  255.     if (!cmdInfo.m_strFileName.IsEmpty())    // open an existing document
  256.         m_nCmdShow = nCmdShow;
  257.     // Dispatch commands specified on the command line
  258.     if (cmdInfo.m_nShellCommand != CCommandLineInfo::FileNew &&
  259.         !ProcessShellCommand(cmdInfo))
  260.     {
  261.         return FALSE;
  262.     }
  263.  
  264.     // Enable File Manager drag/drop open
  265.     m_pMainWnd->DragAcceptFiles();
  266.  
  267.     // When a server application is launched stand-alone, it is a good idea
  268.     //  to update the system registry in case it has been damaged.
  269.     // do registry stuff in separate thread
  270. #ifndef _UNICODE
  271.     if (m_bWin31) // no threads on Win32s
  272.         UpdateRegistry();
  273.     else
  274. #endif
  275.         AfxBeginThread(DoRegistry, this, THREAD_PRIORITY_IDLE);
  276.  
  277.     return TRUE;
  278. }
  279.  
  280. BOOL CWordPadApp::IsDocOpen(LPCTSTR lpszFileName)
  281. {
  282.     if (lpszFileName[0] == NULL)
  283.         return FALSE;
  284.     TCHAR szPath[_MAX_PATH];
  285.     AfxFullPath(szPath, lpszFileName);
  286.     ATOM atom = GlobalAddAtom(szPath);
  287.     ASSERT(atom != NULL);
  288.     if (atom == NULL)
  289.         return FALSE;
  290.     EnumWindows(StaticEnumProc, (LPARAM)&atom);
  291.     if (atom == NULL)
  292.         return TRUE;
  293.     DeleteAtom(atom);
  294.     return FALSE;
  295. }
  296.  
  297. BOOL CALLBACK CWordPadApp::StaticEnumProc(HWND hWnd, LPARAM lParam)
  298. {
  299.     TCHAR szClassName[30];
  300.     GetClassName(hWnd, szClassName, 30);
  301.     if (lstrcmp(szClassName, szWordPadClass) != 0)
  302.         return TRUE;
  303.  
  304.     ATOM* pAtom = (ATOM*)lParam;
  305.     ASSERT(pAtom != NULL);
  306.     DWORD dw = NULL;
  307.     ::SendMessageTimeout(hWnd, m_nOpenMsg, NULL, (LPARAM)*pAtom,
  308.         SMTO_ABORTIFHUNG, 500, &dw);
  309.     if (dw)
  310.     {
  311.         ::SetForegroundWindow(hWnd);
  312.         DeleteAtom(*pAtom);
  313.         *pAtom = NULL;
  314.         return FALSE;
  315.     }                 
  316.     return TRUE;
  317. }
  318.  
  319. void CWordPadApp::RegisterFormats()
  320. {
  321.     cfEmbeddedObject = (CLIPFORMAT)::RegisterClipboardFormat(_T("Embedded Object"));
  322.     cfRTF = (CLIPFORMAT)::RegisterClipboardFormat(_T(CF_RTF));
  323.     cfRTO = (CLIPFORMAT)::RegisterClipboardFormat(_T(CF_RETEXTOBJ));
  324. }
  325.  
  326. CDocOptions& CWordPadApp::GetDocOptions(int nDocType)
  327. {
  328.     switch (nDocType)
  329.     {
  330.         case RD_WINWORD6:
  331.         case RD_WORDPAD:
  332.             return m_optionsWord;
  333.         case RD_RICHTEXT:
  334.             return m_optionsRTF;
  335.         case RD_TEXT:
  336.         case RD_OEMTEXT:
  337.             return m_optionsText;
  338.         case RD_WRITE:
  339.             return m_optionsWrite;
  340.         case RD_EMBEDDED:
  341.             return m_optionsIP;
  342.     }
  343.     ASSERT(FALSE);
  344.     return m_optionsNull;
  345. }
  346.  
  347. CDockState& CWordPadApp::GetDockState(int nDocType, BOOL bPrimary)
  348. {
  349.     return GetDocOptions(nDocType).GetDockState(bPrimary);
  350. }
  351.  
  352. void CWordPadApp::SaveOptions()
  353. {
  354.     WriteProfileInt(szSection, szWordSel, m_bWordSel);
  355.     WriteProfileInt(szSection, szUnits, GetUnits());
  356.     WriteProfileInt(szSection, szMaximized, m_bMaximized);
  357.     WriteProfileBinary(szSection, szFrameRect, (BYTE*)&m_rectInitialFrame, 
  358.         sizeof(CRect));
  359.     WriteProfileBinary(szSection, szPageMargin, (BYTE*)&m_rectPageMargin, 
  360.         sizeof(CRect));
  361.     m_optionsText.SaveOptions(szTextSection);
  362.     m_optionsRTF.SaveOptions(szRTFSection);
  363.     m_optionsWord.SaveOptions(szWordSection);
  364.     m_optionsWrite.SaveOptions(szWriteSection);
  365.     m_optionsIP.SaveOptions(szIPSection);
  366. }
  367.  
  368. void CWordPadApp::LoadOptions()
  369. {
  370.     BYTE* pb = NULL;
  371.     UINT nLen = 0;
  372.  
  373.     HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
  374.     if (hFont == NULL)
  375.         hFont = (HFONT)GetStockObject(ANSI_VAR_FONT);
  376.     VERIFY(GetObject(hFont, sizeof(LOGFONT), &m_lf));
  377.  
  378.     m_bWordSel = GetProfileInt(szSection, szWordSel, TRUE);
  379.     TCHAR buf[2];
  380.     buf[0] = NULL;
  381.     GetLocaleInfo(GetUserDefaultLCID(), LOCALE_IMEASURE, buf, 2);
  382.     int nDefUnits = buf[0] == '1' ? 0 : 1;
  383.     SetUnits(GetProfileInt(szSection, szUnits, nDefUnits));
  384.     m_bMaximized = GetProfileInt(szSection, szMaximized, (int)FALSE);
  385.  
  386.     if (GetProfileBinary(szSection, szFrameRect, &pb, &nLen))
  387.     {
  388.         ASSERT(nLen == sizeof(CRect));
  389.         memcpy(&m_rectInitialFrame, pb, sizeof(CRect));
  390.         delete pb;
  391.     }
  392.     else
  393.         m_rectInitialFrame.SetRect(0,0,0,0);
  394.  
  395.     CRect rectScreen(0, 0, GetSystemMetrics(SM_CXSCREEN), 
  396.         GetSystemMetrics(SM_CYSCREEN));
  397.     CRect rectInt;
  398.     rectInt.IntersectRect(&rectScreen, &m_rectInitialFrame);
  399.     if (rectInt.Width() < 10 || rectInt.Height() < 10)
  400.         m_rectInitialFrame.SetRect(0, 0, 0, 0);
  401.  
  402.     if (GetProfileBinary(szSection, szPageMargin, &pb, &nLen))
  403.     {
  404.         ASSERT(nLen == sizeof(CRect));
  405.         memcpy(&m_rectPageMargin, pb, sizeof(CRect));
  406.         delete pb;
  407.     }
  408.     else
  409.         m_rectPageMargin.SetRect(1800, 1440, 1800, 1440);    
  410.  
  411.     m_optionsText.LoadOptions(szTextSection);
  412.     m_optionsRTF.LoadOptions(szRTFSection);
  413.     m_optionsWord.LoadOptions(szWordSection);
  414.     m_optionsWrite.LoadOptions(szWriteSection);
  415.     m_optionsIP.LoadOptions(szIPSection);
  416. }
  417.  
  418. void CWordPadApp::LoadAbbrevStrings()
  419. {
  420.     for (int i=0;i<m_nNumUnits;i++)
  421.         m_units[i].m_strAbbrev.LoadString(m_units[i].m_nAbbrevID);
  422. }
  423.  
  424. BOOL CWordPadApp::ParseMeasurement(LPTSTR buf, int& lVal)
  425. {
  426.     TCHAR* pch;
  427.     if (buf[0] == NULL)
  428.         return FALSE;
  429.     float f = (float)_tcstod(buf,&pch);
  430.  
  431.     // eat white space, if any
  432.     while (isspace(*pch))
  433.         pch++;
  434.  
  435.     if (pch[0] == NULL) // default
  436.     {
  437.         lVal = (f < 0.f) ? (int)(f*GetTPU()-0.5f) : (int)(f*GetTPU()+0.5f);
  438.         return TRUE;
  439.     }
  440.     for (int i=0;i<m_nNumUnits;i++)
  441.     {
  442.         if (lstrcmpi(pch, GetAbbrev(i)) == 0)
  443.         {
  444.             lVal = (f < 0.f) ? (int)(f*GetTPU(i)-0.5f) : (int)(f*GetTPU(i)+0.5f);
  445.             return TRUE;
  446.         }
  447.     }
  448.     return FALSE;
  449. }
  450.  
  451. void CWordPadApp::PrintTwips(TCHAR* buf, int nValue, int nDec)
  452. {
  453.     ASSERT(nDec == 2);
  454.     int div = GetTPU();
  455.     int lval = nValue;
  456.     BOOL bNeg = FALSE;
  457.     
  458.     int* pVal = new int[nDec+1];
  459.  
  460.     if (lval < 0)
  461.     {
  462.         bNeg = TRUE;
  463.         lval = -lval;
  464.     }
  465.  
  466.     for (int i=0;i<=nDec;i++)
  467.     {
  468.         pVal[i] = lval/div; //integer number
  469.         lval -= pVal[i]*div;
  470.         lval *= 10;
  471.     }
  472.     i--;
  473.     if (lval >= div/2)
  474.         pVal[i]++;
  475.  
  476.     while ((pVal[i] == 10) && (i != 0))
  477.     {
  478.         pVal[i] = 0;
  479.         pVal[--i]++;
  480.     }
  481.  
  482.     while (nDec && pVal[nDec] == 0)
  483.         nDec--;
  484.  
  485.     _stprintf(buf, _T("%.*f"), nDec, (float)nValue/(float)div);
  486.  
  487.     if (m_units[m_nUnits].m_bSpaceAbbrev)
  488.         lstrcat(buf, _T(" "));
  489.     lstrcat(buf, GetAbbrev());
  490.     delete []pVal;
  491. }
  492.  
  493. /////////////////////////////////////////////////////////////////////////////
  494. // CWordPadApp commands
  495.  
  496. void CWordPadApp::OnAppAbout()
  497. {
  498.     CString strTitle;
  499.     VERIFY(strTitle.LoadString(AFX_IDS_APP_TITLE));
  500.     ShellAbout(m_pMainWnd->GetSafeHwnd(), strTitle, _T(""), LoadIcon(IDR_MAINFRAME));
  501. }
  502.  
  503. int CWordPadApp::ExitInstance() 
  504. {
  505.     FreeLibrary(GetModuleHandle(_T("RICHED32.DLL")));
  506.     SaveOptions();
  507.  
  508.     return CWinApp::ExitInstance();
  509. }
  510.  
  511. void CWordPadApp::OnFileNew() 
  512. {
  513.     int nDocType = -1;
  514.     if (!m_bPromptForType)
  515.     {
  516.         if (cmdInfo.m_bForceTextMode)
  517.             nDocType = RD_TEXT;
  518.         else if (!cmdInfo.m_strFileName.IsEmpty())
  519.         {
  520.             CFileException fe;
  521.             nDocType = GetDocTypeFromName(cmdInfo.m_strFileName, fe);
  522.         }
  523.         if (nDocType == -1)
  524.             nDocType = RD_DEFAULT;
  525.     }
  526.     else
  527.     {
  528.         CFileNewDialog dlg;
  529.         if (dlg.DoModal() == IDCANCEL)
  530.             return;
  531.  
  532.         nDocType = (dlg.m_nSel == 0) ? RD_DEFAULT:    //Word 6
  533.                     (dlg.m_nSel == 1) ? RD_RICHTEXT :    //RTF
  534.                     RD_TEXT ;                    //text
  535.  
  536.         if (nDocType != RD_TEXT)
  537.             cmdInfo.m_bForceTextMode = FALSE;
  538.     }
  539.     m_nNewDocType = nDocType;
  540.     DocTemplate.OpenDocumentFile(NULL);
  541.         // if returns NULL, the user has already been alerted
  542. }
  543.  
  544. // prompt for file name - used for open and save as
  545. // static function called from app
  546. BOOL CWordPadApp::PromptForFileName(CString& fileName, UINT nIDSTitle, 
  547.     DWORD dwFlags, BOOL bOpenFileDialog, int* pType)
  548. {
  549.     ScanForConverters();
  550.     CFileDialog dlgFile(bOpenFileDialog);
  551.     CString title;
  552.  
  553.     VERIFY(title.LoadString(nIDSTitle));
  554.     
  555.     dlgFile.m_ofn.Flags |= dwFlags;
  556. //    dlgFile.m_ofn.Flags &= ~OFN_SHOWHELP;
  557.  
  558.     int nIndex = m_nFilterIndex;
  559.     if (!bOpenFileDialog)
  560.     {
  561.         int nDocType = (pType != NULL) ? *pType : RD_DEFAULT;
  562.         nIndex = GetIndexFromType(nDocType, bOpenFileDialog);
  563.         if (nIndex == -1)
  564.             nIndex = GetIndexFromType(RD_DEFAULT, bOpenFileDialog);
  565.         if (nIndex == -1)
  566.             nIndex = GetIndexFromType(RD_NATIVE, bOpenFileDialog);
  567.         ASSERT(nIndex != -1);
  568.         nIndex++;
  569.     }
  570.     dlgFile.m_ofn.nFilterIndex = nIndex;
  571.     // strDefExt is necessary to hold onto the memory from GetExtFromType
  572.     CString strDefExt = GetExtFromType(GetTypeFromIndex(nIndex-1, bOpenFileDialog));
  573.     dlgFile.m_ofn.lpstrDefExt = strDefExt;
  574.         
  575.  
  576.     CString strFilter = GetFileTypes(bOpenFileDialog);
  577.     dlgFile.m_ofn.lpstrFilter = strFilter;
  578.     dlgFile.m_ofn.lpstrTitle = title;
  579.     dlgFile.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH);
  580.  
  581.     BOOL bRet = (dlgFile.DoModal() == IDOK) ? TRUE : FALSE;
  582.     fileName.ReleaseBuffer();
  583.     if (bRet)
  584.     {
  585.         if (bOpenFileDialog)
  586.             m_nFilterIndex = dlgFile.m_ofn.nFilterIndex;
  587.         if (pType != NULL)
  588.         {
  589.             int nIndex = (int)dlgFile.m_ofn.nFilterIndex - 1;
  590.             ASSERT(nIndex >= 0);
  591.             *pType = GetTypeFromIndex(nIndex, bOpenFileDialog);
  592.         }
  593.     }
  594.     return bRet;
  595. }
  596.  
  597. void CWordPadApp::OnFileOpen() 
  598. {
  599.     // prompt the user (with all document templates)
  600.     CString newName;
  601.     int nType = RD_DEFAULT;
  602.     if (!PromptForFileName(newName, AFX_IDS_OPENFILE,
  603.       OFN_HIDEREADONLY | OFN_FILEMUSTEXIST, TRUE, &nType))
  604.         return; // open cancelled
  605.  
  606.     if (nType == RD_OEMTEXT)
  607.         m_bForceOEM = TRUE;
  608.     OpenDocumentFile(newName);
  609.     m_bForceOEM = FALSE;
  610.     // if returns NULL, the user has already been alerted
  611. }
  612.  
  613. BOOL CWordPadApp::OnDDECommand(LPTSTR /*lpszCommand*/) 
  614. {
  615.     return FALSE;
  616. }
  617.  
  618. /////////////////////////////////////////////////////////////////////////////
  619. // DDE and ShellExecute support
  620.  
  621. //HKEY_CLASSES_ROOT\.RTF = rtffile
  622. //HKEY_CLASSES_ROOT\rtffile = 
  623. //HKEY_CLASSES_ROOT\rtffile\CLSID = {73FDDC80-AEA9-101A-98A7-00AA00374959} 
  624. //HKEY_CLASSES_ROOT\rtffile\protocol\StdFileEditing\server = WORDPAD.EXE
  625. //HKEY_CLASSES_ROOT\rtffile\protocol\StdFileEditing\verb\0 = &Edit
  626. //HKEY_CLASSES_ROOT\rtffile\shell\open\command = WORDPAD.EXE %1
  627. //HKEY_CLASSES_ROOT\rtffile\shell\print\command = WORDPAD.EXE /p %1
  628.  
  629. #define REGENTRY(key, value) _T(key) _T("\0\0") _T(value)
  630. #define REGENTRYX(key, valuename, value) _T(key) _T("\0") _T(valuename) _T("\0") _T(value)
  631.  
  632. static const TCHAR sz00[] = REGENTRY("%2", "%5");
  633. static const TCHAR sz01[] = REGENTRY("%2\\CLSID", "%1");
  634. static const TCHAR sz02[] = REGENTRY("%2\\Insertable", "");
  635. static const TCHAR sz03[] = REGENTRY("%2\\protocol\\StdFileEditing\\verb\\0", "&Edit");
  636. static const TCHAR sz04[] = REGENTRY("%2\\protocol\\StdFileEditing\\server", "%3");
  637. static const TCHAR sz05[] = REGENTRY("CLSID\\%1", "%5");
  638. static const TCHAR sz06[] = REGENTRY("CLSID\\%1\\ProgID", "%2");
  639. static const TCHAR sz07[] = REGENTRY("CLSID\\%1\\InprocHandler32", "ole32.dll");
  640. static const TCHAR sz08[] = REGENTRY("CLSID\\%1\\LocalServer32", "%3");
  641. static const TCHAR sz09[] = REGENTRY("CLSID\\%1\\Verb\\0", "&Edit,0,2");
  642. static const TCHAR sz10[] = REGENTRY("CLSID\\%1\\Verb\\1", "&Open,0,2");
  643. static const TCHAR sz11[] = REGENTRY("CLSID\\%1\\Insertable", "");
  644. static const TCHAR sz12[] = REGENTRY("CLSID\\%1\\AuxUserType\\2", "%4");
  645. static const TCHAR sz13[] = REGENTRY("CLSID\\%1\\AuxUserType\\3", "%6");
  646. static const TCHAR sz14[] = REGENTRY("CLSID\\%1\\DefaultIcon", "%3,1");
  647. static const TCHAR sz15[] = REGENTRY("CLSID\\%1\\MiscStatus", "0");
  648. static const TCHAR sz16[] = REGENTRY("%2\\shell\\open\\command", "%3 \"%%1\"");
  649. static const TCHAR sz17[] = REGENTRY("%2\\shell\\print\\command", "%3 /p \"%%1\"");
  650. static const TCHAR sz18[] = REGENTRY("%7", "%2");
  651. static const TCHAR sz19[] = REGENTRY("%2", ""); // like sz00 only no long type name
  652. static const TCHAR sz20[] = REGENTRY("%2\\shell\\printto\\command", "%3 /pt \"%%1\" \"%%2\" \"%%3\" \"%%4\"");
  653. static const TCHAR sz21[] = REGENTRY("%2\\DefaultIcon", "%3,%8");
  654. static const TCHAR sz22[] = REGENTRYX("%7\\ShellNew", "NullFile", "true");
  655. static const TCHAR sz23[] = REGENTRYX("%7\\ShellNew", "Data", "{\\rtf1}");
  656.  
  657. // %1 - class ID
  658. // %2 - class name                WordPad.Document.1
  659. // %3 - SFN executable path        C:\PROGRA~1\ACCESS~1\WORDPAD.EXE
  660. // %4 - short type name            Document
  661. // %5 - long type name            Microsoft WordPad Document
  662. // %6 - long application name    Microsoft WordPad
  663. // %7 = extension                .rtf
  664. // %8 = default icon            0,1,2,3
  665. #define NUM_REG_ARGS 8
  666.  
  667. static const LPCTSTR rglpszWordPadRegister[] =
  668. {sz00, sz02, sz03, sz05, sz09, sz10, sz11, sz15, NULL};
  669.  
  670. static const LPCTSTR rglpszWordPadOverwrite[] =
  671. {sz01, sz04, sz06, sz07, sz08, sz12, sz13, sz14, sz16, sz17, sz20, NULL};
  672.  
  673. //static const LPCTSTR rglpszExtRegister[] =
  674. //{sz00, sz18, NULL};
  675.  
  676. //static const LPCTSTR rglpszExtOverwrite[] =
  677. //{sz01, sz16, sz17, sz21, NULL};
  678.  
  679. static const LPCTSTR rglpszWriExtRegister[] =
  680. {sz18, NULL};
  681. static const LPCTSTR rglpszWriRegister[] =
  682. {sz00, sz01, sz16, sz17, sz20, sz21, NULL};
  683.  
  684. static const LPCTSTR rglpszRtfExtRegister[] =
  685. {sz18, sz23, NULL};
  686. static const LPCTSTR rglpszRtfRegister[] =
  687. {sz00, sz01, sz16, sz17, sz20, sz21, NULL};
  688.  
  689. static const LPCTSTR rglpszTxtExtRegister[] =
  690. {sz18, sz22, NULL};
  691. static const LPCTSTR rglpszTxtRegister[] =
  692. {sz00, sz01, sz16, sz17, sz20, sz21, NULL};
  693.  
  694. static const LPCTSTR rglpszDocExtRegister[] =
  695. {sz18, sz22, NULL};
  696. static const LPCTSTR rglpszDocRegister[] =
  697. {sz00, sz01, sz16, sz17, sz20, sz21, NULL};
  698.  
  699. static void RegisterExt(LPCTSTR lpszExt, LPCTSTR lpszProgID, UINT nIDTypeName,
  700.     LPCTSTR* rglpszSymbols, LPCTSTR* rglpszExtRegister, 
  701.     LPCTSTR* rglpszRegister, int nIcon)
  702. {
  703.     // don't overwrite anything with the extensions
  704.     CString strWhole;
  705.     VERIFY(strWhole.LoadString(nIDTypeName));
  706.     CString str;
  707.     AfxExtractSubString(str, strWhole, DOCTYPE_PROGID);
  708.  
  709.     rglpszSymbols[1] = lpszProgID;
  710.     rglpszSymbols[4] = str;
  711.     rglpszSymbols[6] = lpszExt;
  712.     TCHAR buf[10];
  713.     wsprintf(buf, _T("%d"), nIcon);
  714.     rglpszSymbols[7] = buf;
  715.     // check for .ext and progid
  716.     CKey key;
  717.     if (!key.Open(HKEY_CLASSES_ROOT, lpszExt)) // .ext doesn't exist
  718.         RegisterHelper(rglpszExtRegister, rglpszSymbols, TRUE);
  719.     key.Close();
  720.     if (!key.Open(HKEY_CLASSES_ROOT, lpszProgID)) // ProgID doesn't exist (i.e. txtfile)
  721.         RegisterHelper(rglpszRegister, rglpszSymbols, TRUE);
  722. }
  723.  
  724. void CWordPadApp::UpdateRegistry()
  725. {
  726.     USES_CONVERSION;
  727.     LPOLESTR lpszClassID = NULL;
  728.     CDocTemplate* pDocTemplate = &DocTemplate;
  729.  
  730.     // get registration info from doc template string
  731.     CString strServerName;
  732.     CString strLocalServerName;
  733.     CString strLocalShortName;
  734.  
  735.     if (!pDocTemplate->GetDocString(strServerName,
  736.        CDocTemplate::regFileTypeId) || strServerName.IsEmpty())
  737.     {
  738.         TRACE0("Error: not enough information in DocTemplate to register OLE server.\n");
  739.         return;
  740.     }
  741.     if (!pDocTemplate->GetDocString(strLocalServerName,
  742.        CDocTemplate::regFileTypeName))
  743.         strLocalServerName = strServerName;     // use non-localized name
  744.     if (!pDocTemplate->GetDocString(strLocalShortName,
  745.         CDocTemplate::fileNewName))
  746.         strLocalShortName = strLocalServerName; // use long name
  747.  
  748.     ASSERT(strServerName.Find(' ') == -1);  // no spaces allowed
  749.  
  750.     ::StringFromCLSID(clsid, &lpszClassID);
  751.     ASSERT (lpszClassID != NULL);
  752.  
  753.     // get path name to server
  754.     TCHAR szLongPathName[_MAX_PATH];
  755.     TCHAR szShortPathName[_MAX_PATH];
  756.     ::GetModuleFileName(AfxGetInstanceHandle(), szLongPathName, _MAX_PATH);
  757.     ::GetShortPathName(szLongPathName, szShortPathName, _MAX_PATH);
  758.     
  759.     LPCTSTR rglpszSymbols[NUM_REG_ARGS];
  760.     rglpszSymbols[0] = OLE2CT(lpszClassID);
  761.     rglpszSymbols[1] = strServerName;
  762.     rglpszSymbols[2] = szShortPathName;
  763.     rglpszSymbols[3] = strLocalShortName;
  764.     rglpszSymbols[4] = strLocalServerName;
  765.     rglpszSymbols[5] = m_pszAppName;    // will usually be long, readable name
  766.     rglpszSymbols[6] = NULL;
  767.  
  768.     if (RegisterHelper((LPCTSTR*)rglpszWordPadRegister, rglpszSymbols, FALSE))
  769.         RegisterHelper((LPCTSTR*)rglpszWordPadOverwrite, rglpszSymbols, TRUE);
  770.  
  771. //    RegisterExt(_T(".txt"), _T("txtfile"), IDS_TEXT_DOC, rglpszSymbols, 
  772. //        (LPCTSTR*)rglpszTxtExtRegister, (LPCTSTR*)rglpszTxtRegister, 3);
  773.     RegisterExt(_T(".rtf"), _T("rtffile"), IDS_RICHTEXT_DOC, rglpszSymbols, 
  774.         (LPCTSTR*)rglpszRtfExtRegister, (LPCTSTR*)rglpszRtfRegister, 1);
  775.     RegisterExt(_T(".wri"), _T("wrifile"), IDS_WRITE_DOC, rglpszSymbols, 
  776.         (LPCTSTR*)rglpszWriExtRegister, (LPCTSTR*)rglpszWriRegister, 2);
  777.     RegisterExt(_T(".doc"), _T("WordPad.Document.1"), IDS_WINWORD6_DOC, rglpszSymbols, 
  778.         (LPCTSTR*)rglpszDocExtRegister, (LPCTSTR*)rglpszDocRegister, 1);
  779.  
  780.     // free memory for class ID
  781.     ASSERT(lpszClassID != NULL);
  782.     CoTaskMemFree(lpszClassID);
  783. }
  784.  
  785. BOOL RegisterHelper(LPCTSTR* rglpszRegister, LPCTSTR* rglpszSymbols, 
  786.     BOOL bReplace)
  787. {
  788.     ASSERT(rglpszRegister != NULL);
  789.     ASSERT(rglpszSymbols != NULL);
  790.  
  791.     CString strKey;
  792.     CString strValueName;
  793.     CString strValue;
  794.  
  795.     // keeping a key open makes this go a bit faster
  796.     CKey keyTemp;
  797.     VERIFY(keyTemp.Create(HKEY_CLASSES_ROOT, _T("CLSID")));
  798.  
  799.     BOOL bResult = TRUE;
  800.     while (*rglpszRegister != NULL)
  801.     {
  802.         LPCTSTR lpszKey = *rglpszRegister++;
  803.         if (*lpszKey == '\0')
  804.             continue;
  805.  
  806.         LPCTSTR lpszValueName = lpszKey + lstrlen(lpszKey) + 1;
  807.         LPCTSTR lpszValue = lpszValueName + lstrlen(lpszValueName) + 1;
  808.  
  809.         strKey.ReleaseBuffer(
  810.             FormatMessage(FORMAT_MESSAGE_FROM_STRING | 
  811.             FORMAT_MESSAGE_ARGUMENT_ARRAY, lpszKey, NULL,    NULL, 
  812.             strKey.GetBuffer(256), 256, (va_list*) rglpszSymbols));
  813.         strValueName = lpszValueName;
  814.         strValue.ReleaseBuffer(
  815.             FormatMessage(FORMAT_MESSAGE_FROM_STRING | 
  816.             FORMAT_MESSAGE_ARGUMENT_ARRAY, lpszValue, NULL, NULL, 
  817.             strValue.GetBuffer(256), 256, (va_list*) rglpszSymbols));
  818.  
  819.         if (strKey.IsEmpty())
  820.         {
  821.             TRACE1("Warning: skipping empty key '%s'.\n", lpszKey);
  822.             continue;
  823.         }
  824.  
  825.         CKey key;
  826.         VERIFY(key.Create(HKEY_CLASSES_ROOT, strKey));
  827.         if (!bReplace)
  828.         {
  829.             CString str;
  830.             if (key.GetStringValue(str, strValueName) && !str.IsEmpty())
  831.                 continue;
  832.         }
  833.  
  834.         if (!key.SetStringValue(strValue, strValueName))
  835.         {
  836.             TRACE2("Error: failed setting key '%s' to value '%s'.\n",
  837.                 (LPCTSTR)strKey, (LPCTSTR)strValue);
  838.             bResult = FALSE;
  839.             break;
  840.         }
  841.     }
  842.  
  843.     return bResult;
  844. }
  845.  
  846. void CWordPadApp::WinHelp(DWORD dwData, UINT nCmd) 
  847. {
  848.     if (nCmd == HELP_INDEX || nCmd == HELP_CONTENTS)
  849.         nCmd = HELP_FINDER;
  850.     CWinApp::WinHelp(dwData, nCmd);
  851. }
  852.  
  853. BOOL CWordPadApp::PreTranslateMessage(MSG* pMsg) 
  854. {
  855.     if (pMsg->message == WM_PAINT)
  856.         return FALSE;
  857.     // CWinApp::PreTranslateMessage does nothing but call base
  858.     return CWinThread::PreTranslateMessage(pMsg);
  859. }
  860.  
  861. void CWordPadApp::NotifyPrinterChanged(BOOL bUpdatePrinterSelection)
  862. {
  863.     if (bUpdatePrinterSelection)
  864.         UpdatePrinterSelection(FALSE);
  865.     POSITION pos = m_listPrinterNotify.GetHeadPosition();
  866.     while (pos != NULL)
  867.     {
  868.         HWND hWnd = m_listPrinterNotify.GetNext(pos);
  869.         ::SendMessage(hWnd, m_nPrinterChangedMsg, 0, 0);
  870.     }
  871. }
  872.  
  873. BOOL CWordPadApp::IsIdleMessage(MSG* pMsg)
  874. {
  875.     if (pMsg->message == WM_MOUSEMOVE || pMsg->message == WM_NCMOUSEMOVE)
  876.         return FALSE;
  877.     return CWinApp::IsIdleMessage(pMsg);
  878. }
  879.  
  880. HGLOBAL CWordPadApp::CreateDevNames()
  881. {
  882.     HGLOBAL hDev = NULL;
  883.     if (!cmdInfo.m_strDriverName.IsEmpty() && !cmdInfo.m_strPrinterName.IsEmpty() &&
  884.         !cmdInfo.m_strPortName.IsEmpty())
  885.     {
  886.         hDev = GlobalAlloc(GPTR, 4*sizeof(WORD)+
  887.             cmdInfo.m_strDriverName.GetLength() + 1 +
  888.             cmdInfo.m_strPrinterName.GetLength() + 1 +
  889.             cmdInfo.m_strPortName.GetLength()+1);
  890.         LPDEVNAMES lpDev = (LPDEVNAMES)GlobalLock(hDev);
  891.         lpDev->wDriverOffset = sizeof(WORD)*4;
  892.         lstrcpy((TCHAR*)lpDev + lpDev->wDriverOffset, cmdInfo.m_strDriverName);
  893.  
  894.         lpDev->wDeviceOffset = (WORD)(lpDev->wDriverOffset + cmdInfo.m_strDriverName.GetLength()+1);
  895.         lstrcpy((TCHAR*)lpDev + lpDev->wDeviceOffset, cmdInfo.m_strPrinterName);
  896.  
  897.         lpDev->wOutputOffset = (WORD)(lpDev->wDeviceOffset + cmdInfo.m_strPrinterName.GetLength()+1);
  898.         lstrcpy((TCHAR*)lpDev + lpDev->wOutputOffset, cmdInfo.m_strPortName);
  899.  
  900.         lpDev->wDefault = 0;
  901.     }
  902.     return hDev;
  903. }
  904.